    <!DOCTYPE html>
<html lang="zh-cn">
	<head>
		<meta charset="utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
		<meta name="viewport" content="width=device-width, initial-scale=1">
		
		<meta name="description" content="Nodejh&#39;s Blog">
		<meta name="generator" content="Hugo 0.31.1" />
		<title>深入理解 Oracle 启动原理 &middot; node</title>
		<link rel="shortcut icon" href="http://nodejh.com/images/favicon.ico">
		<link rel="stylesheet" href="http://nodejh.com/css/style.css">
		<link rel="stylesheet" href="http://nodejh.com/css/highlight.css">
		

		
		<link rel="stylesheet" href="http://nodejh.com/css/font-awesome.min.css">
		

		
		<link href="http://nodejh.com/index.xml" rel="alternate" type="application/rss+xml" title="node" />
		
	</head>

    <body>
       <nav class="main-nav">
	
	
		<a href='http://nodejh.com/'> <span class="arrow">←</span>Home</a>
	
	<a href='http://nodejh.com/post'>Archive</a>
	<a href='http://nodejh.com/tags'>Tags</a>
	<a href='http://nodejh.com/projects'>Projects</a>
	<a href='http://nodejh.com/about'>About</a>

	

	
	<a class="cta" href="http://nodejh.com/index.xml">Subscribe</a>
	
</nav>


        <section id="wrapper" class="post">
            <article>
                <header>
                    <h1>
                        深入理解 Oracle 启动原理
                    </h1>
                    <h2 class="headline">
                    Mar 26, 2017 00:42
                    · 4622 words
                    · 10 minutes read
                      <span class="tags">
                      
                      
                          
                              <a href="http://nodejh.com/tags/%E6%95%B0%E6%8D%AE%E5%BA%93">数据库</a>
                          
                              <a href="http://nodejh.com/tags/oracle">Oracle</a>
                          
                              <a href="http://nodejh.com/tags/database">Database</a>
                          
                      
                      
                      </span>
                    </h2>
                </header>
                
                  
                    <div id="toc">
                      <nav id="TableOfContents">
<ul>
<li>
<ul>
<li><a href="#一-常用启动步骤">一. 常用启动步骤</a>
<ul>
<li>
<ul>
<li><a href="#1-1-启动监听器">1.1. 启动监听器</a></li>
<li><a href="#1-2-启动数据库">1.2. 启动数据库</a></li>
<li><a href="#1-3-启动-oem">1.3. 启动 OEM</a></li>
</ul></li>
</ul></li>
<li><a href="#二-启动概述">二. 启动概述</a></li>
<li><a href="#三-启动详解">三. 启动详解</a>
<ul>
<li>
<ul>
<li><a href="#3-1-shutdown-状态">3.1. <code>shutdown</code> 状态</a></li>
<li><a href="#3-2-启动实例-shutdown-nomount">3.2. 启动实例 <code>shutdown --&gt; nomount</code></a>
<ul>
<li>
<ul>
<li><a href="#3-2-1-读取参数文件">3.2.1 读取参数文件</a></li>
<li><a href="#3-2-2-分配-sga">3.2.2 分配 SGA</a></li>
<li><a href="#3-2-3-启动后台进程">3.2.3 启动后台进程</a></li>
<li><a href="#3-2-4-打开告警文件和跟踪文件">3.2.4 打开告警文件和跟踪文件</a></li>
</ul></li>
</ul></li>
<li><a href="#3-3-装载数据库-nomunt-mount">3.3 装载数据库 <code>nomunt --&gt; mount</code></a>
<ul>
<li>
<ul>
<li><a href="#3-3-1-装载数据库概述">3.3.1 装载数据库概述</a></li>
<li><a href="#3-3-2-可以查询控制文件">3.3.2 可以查询控制文件</a></li>
<li><a href="#3-3-3-不能查询表-视图">3.3.3 不能查询表、视图</a></li>
</ul></li>
</ul></li>
<li><a href="#3-4-打开数据库-mount-open">3.4 打开数据库 <code>mount --&gt; open</code></a></li>
</ul></li>
</ul></li>
<li><a href="#四-关闭数据库">四. 关闭数据库</a>
<ul>
<li>
<ul>
<li><a href="#4-1-normal">4.1. NORMAL</a></li>
<li><a href="#4-2-transaction">4.2. TRANSACTION</a></li>
<li><a href="#4-3-immediate">4.3. IMMEDIATE</a></li>
</ul></li>
</ul></li>
<li><a href="#五-为什么分为三步">五. 为什么分为三步</a></li>
<li><a href="#六-常见连接错误">六. 常见连接错误</a>
<ul>
<li>
<ul>
<li><a href="#1-未启动数据库实例">1. 未启动数据库实例</a></li>
<li><a href="#2-未启动监听器">2. 未启动监听器</a></li>
</ul></li>
</ul></li>
</ul></li>
</ul>
</nav>
                    </div>
                  
                
                <section id="post-body">
                    <h2 id="一-常用启动步骤">一. 常用启动步骤</h2>

<p>对于普通用户，如果需要使用 Oracle 数据库，需要两个启动步骤：启动数据库和启动监听器。</p>

<p></p>

<p>如果还需要使用 OEM 来监控数据库服务，则还要启动 OEM。</p>

<h4 id="1-1-启动监听器">1.1. 启动监听器</h4>

<p>Oracle 监听器是一个独立的后台进程，用于监听客户端向数据库服务器端提出的连接请求，它是客户端和服务器端通讯的桥梁。</p>

<p>启动监听器：</p>

<pre><code>$ lsnrctl start
</code></pre>

<h4 id="1-2-启动数据库">1.2. 启动数据库</h4>

<p>我们可以使用 <code>sqlplus</code> 来启动数据库。关于 <code>sqlplus</code> 的详细使用方法请参考 <a href="https://github.com/nodejh/nodejh.github.io/issues/31">《使用 SQL *Plus 管理 Oracle 数据库》</a>。</p>

<p>进入 <code>sqlplus</code> ：</p>

<pre><code>$ sqlplus / as sysdba
</code></pre>

<p>启动数据库：</p>

<pre><code>&gt;SQL startup
</code></pre>

<p>完成这两个步骤，就可以使用数据库了。</p>

<h4 id="1-3-启动-oem">1.3. 启动 OEM</h4>

<p>Oracle Enterprise Manager（Oracle企业管理器，简称 OEM ）是一个图形化数据库管理工具，可同时监控管理多个系统上的多个数据库，因而特别适合分布式环境。</p>

<p>启动 OEM：</p>

<pre><code>$ emctl start dbconsole
</code></pre>

<p>启动成功后就可以通过 <code>http://服务器:1158/em</code> 来访问基于 Web 的监控页面。</p>

<h2 id="二-启动概述">二. 启动概述</h2>

<p>Oracle Serve 由实例（Instance）和数据库（database）组成，每一个运行的 Oracle 数据库都与一个 Oracle 实例关联。</p>

<p>实例是由一组后台进程和一块称为系统全局区 SGA（System Global Area）的共享内存段组成。后台进程是数据库和操作系统进行交互的通道，后台进程的命名由 ORACLE_SID 决定，Oracle 根据 ORACLE_SID 来寻找参数文件启动实例。数据库是指存储在磁盘上的一组物理文件。</p>

<p>Oracle 数据库具有四种状态，启动过程具有三个阶段。</p>

<p>四种状态分别 <code>shutdown</code> <code>nomount</code> <code>mount</code> <code>open</code>，对应三个阶段分别为：</p>

<ul>
<li>启动实例 <code>shutdown --&gt; nomount</code></li>
<li>装载数据库 <code>nomount --&gt; mount</code></li>
<li>打开数据库 <code>mount --&gt; open</code></li>
</ul>

<pre><code>                                                    ^
                                           open     |
                                     +--------------|
                                     |   All files
                                     |   opened as
                                     | described by
                              mount  |  the control
                       +-------------+ file for this
                       | Control file    instance
                       |    opened
                       |   for this
               nomount |   instance
           +-----------+
           |  Instance
           |   started
           |
  shutdown |
-----------+
</code></pre>

<p>启动实例后，Oracle 软件会将实例与特定的数据库关联，这个过程称为装载数据库。接下来可以打开数据库，以便授权用户访问数据库。在同一台计算机上可以并发执行多个实例，每一个实例只访问自己的物理数据库。</p>

<h2 id="三-启动详解">三. 启动详解</h2>

<p>为了弄清楚 Oracle 启动过程的详细内容，我们需要用到两个命令：</p>

<ul>
<li><code>ps</code> 用来查看系统运行了哪些进程</li>
<li><code>ipcs</code> 查询进程间通信设施状态，显示使用了共享内存和信号量</li>
</ul>

<h4 id="3-1-shutdown-状态">3.1. <code>shutdown</code> 状态</h4>

<p>当 Oracle 处于该状态的时候，Oracle 的所有文件都静静的躺在磁盘里，一切都还未开始，属于关机状态。</p>

<pre><code>$ ps -ef | grep oracle
oracle    4524     1  0 00:54 ?        00:00:39 /data/oracle/product/11.2.0/db_1/bin/emagent
root     12825   974  0 13:49 ?        00:00:00 sshd: oracle [priv]
oracle   12832 12825  0 13:49 ?        00:00:00 sshd: oracle@pts/0
oracle   12833 12832  0 13:49 pts/0    00:00:00 -bash
oracle   13825 12833  0 13:54 pts/0    00:00:00 ps -ef
oracle   13826 12833  0 13:54 pts/0    00:00:00 grep --color=auto oracle
$ ipcs -a

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x011268f0 458753     root       600        1000       8

------ Semaphore Arrays --------
key        semid      owner      perms      nsems
</code></pre>

<h4 id="3-2-启动实例-shutdown-nomount">3.2. 启动实例 <code>shutdown --&gt; nomount</code></h4>

<p>总体来说，启动数据库实例包括以下操作：</p>

<ol>
<li>读取参数文件 <code>SPFILE</code></li>
<li>分配 SGA</li>
<li>启动后台进程</li>
<li>打开告警文件和跟踪文件</li>
</ol>

<p>在启动实例时，将为实例创建一系列后台进程和服务进程，并且在内存中创建 SGA 区等内存结构。在实例启动的过程中只会使用到初始化参数文件，数据库是否存在对实例的启动没有影响。如果初化参数设置有误，实例将无法启动。</p>

<p>启动数据库实例的命令如下：</p>

<pre><code>$ sqlplus / as sysdba

SQL*Plus: Release 11.2.0.1.0 Production on Sun Mar 26 14:05:14 2017

Copyright (c) 1982, 2009, Oracle.  All rights reserved.

Connected to an idle instance.

SQL&gt; startup nomount
ORACLE instance started.

Total System Global Area 3273641984 bytes
Fixed Size		    2217792 bytes
Variable Size		 2432698560 bytes
Database Buffers	  822083584 bytes
Redo Buffers		   16642048 bytes
</code></pre>

<p>启动数据库实例后，只会创建实例（即创建 Oracle 实例的各种内存结构与服务进程），并不加载数据库，也不会打开任何数据文件。</p>

<p><strong>测试数据文件能否打开：</strong></p>

<pre><code class="language-sql">SQL&gt; select * from v$datafile;
select * from v$datafile
              *
ERROR at line 1:
ORA-01507: database not mounted
</code></pre>

<p><code>select * from v$datafile</code> 的时候报错，说明数据库文件在 <code>nomount</code> 状态下是无法访问的，因为数据字典需要从控制文件获取文件的信息，而此时控制文件没有打开所以无法查看。</p>

<p>但是在 <code>nomount</code> 状态下可以通过参数文件获得控制文件的位置，因为此时参数文件已经打开：</p>

<pre><code class="language-sql">SQL&gt; show parameter control_files;

NAME				     TYPE
------------------------------------
VALUE
------------------------------
control_files			     string
/data/oracle/oradata/orcl/cont
rol01.ctl, /data/oracle/flash_
recovery_area/orcl/control02.c
tl
</code></pre>

<h6 id="3-2-1-读取参数文件">3.2.1 读取参数文件</h6>

<p>启动数据库实例首先会读取 <code>SPFILE</code> 文件中的初始化参数，如果 <code>SPFILE</code> 文件不存在，则会读取初始化文件。Linux 系统的 <code>SPFILE</code> 文件在 <code>$ORACLE_HOME/dbs</code> 目录下，Windows NT 和 Windows 2000 中 <code>SPFILE</code> 文件目录在 <code>%ORACLE_HOME%\database</code>。文件的读取顺序如下：</p>

<ul>
<li><code>spfile$ORACLE_SID.ora</code></li>
<li><code>spfile.ora</code></li>
<li><code>init$ORACLE_SID.ora</code></li>
</ul>

<p>其中 <code>spfile$ORACLE_SID.ora</code> 和 <code>spfile.ora</code> 属于 <code>SPFILE</code> 文件，<code>init$ORACLE_SID.ora</code> 是初始化文件。</p>

<blockquote>
<p>查看 <code>$ORACLE_HOME</code> 和 <code>$ORACLE_SID</code> 的值可使用 <code>echo</code> 命令，如 <code>echo $ORACLE_HOME</code>。</p>
</blockquote>

<h6 id="3-2-2-分配-sga">3.2.2 分配 SGA</h6>

<p>读取到参数文件之后，Oracle 会根据参数文件分配 SGA（System Global Area）。</p>

<p>SGA 是一个非常庞大的内存区间，这也是为什么开启 Oracle 之后占用了很大内存的原因。SGA 由所有服务进程和后台进程共享。</p>

<p>我们可以通过 <code>show sga</code> 或 <code>select * from v$sga</code> 查看 SGA 的大小：</p>

<pre><code class="language-sql">SQL&gt; show sga;
Total System Global Area 3273641984 bytes
Fixed Size		    2217792 bytes
Variable Size		 2432698560 bytes
Database Buffers	  822083584 bytes
Redo Buffers		   16642048 bytes

SQL&gt; select * from v$sga;

NAME					      VALUE
---------------------------------------- ----------
Fixed Size				    2217792
Variable Size				 2432698560
Database Buffers			  822083584
Redo Buffers				   16642048

</code></pre>

<p>SGA 分为不同的池，我们可以通过视图 <code>v$sgastat</code> 查看：</p>

<pre><code class="language-sql">SQL&gt; select pool,sum(bytes) bytes from v$sgastat group by pool;

POOL			      BYTES
------------------------ ----------
java pool		   16777216
large pool		   16777216
shared pool		 1258295992
			  840943424

</code></pre>

<h6 id="3-2-3-启动后台进程">3.2.3 启动后台进程</h6>

<p>其中有 5 个进程必须启动， DBWR、LGWR、SMON、PMON、CKPT。</p>

<p><code>SMON</code> 系统监视器（System Monitor）。如果 Oracle 实例失败，则在 SGA 中的任何没有写到磁盘中的数据都会丢失。有许多情况可能引起 Oracle 实例失败，例如操作系统的崩溃就会引起 Oracle 实例的失败。当实例失败之后，如果重新打开该数据库，则后台进程 SMON 自动执行实例的复原操作。</p>

<p><code>DBWR</code> 数据库书写器（Database Write）。该服务器进程在缓冲存储区中记录所有的变化和数据。DBWR 把来自数据库的缓冲存储区中的脏数据写到数据文件中，以便确保数据库缓冲存储区中有足够的空闲的缓冲存储区。脏数据就是正在使用但是没有写到数据文件中的数据。</p>

<p><code>LGWR</code> 日志书写器（Log Write）。LGWR 负责把重做日志缓冲存储区中的数据写入到重做日志文件中。</p>

<p><code>CKPT</code> 检查点（Checkpoint）。该进程可以用来同步化数据库的文件，它可以把日志中的文件写入到数据库中。</p>

<p><code>PMON</code> 进程监视器（Process Monitor）。当取消当前的事务，或释放进程占用的锁以及释放其它资源之后，PMON 进程清空那些失败的进程。</p>

<p><strong>查看系统进程和通信设施状态：</strong></p>

<pre><code>$ ps -ef | grep oracle
oracle    4524     1  0 Mar26 ?        00:01:25 /data/oracle/product/11.2.0/db_1/bin/emagent
root      9797   974  0 00:57 ?        00:00:00 sshd: oracle [priv]
oracle    9805  9797  0 00:57 ?        00:00:00 sshd: oracle@pts/0
oracle    9806  9805  0 00:57 pts/0    00:00:00 -bash
oracle   10020     1  0 00:58 ?        00:00:00 ora_pmon_orcl
oracle   10022     1  0 00:58 ?        00:00:01 ora_vktm_orcl
oracle   10026     1  0 00:58 ?        00:00:00 ora_gen0_orcl
oracle   10028     1  0 00:58 ?        00:00:00 ora_diag_orcl
oracle   10030     1  0 00:58 ?        00:00:00 ora_dbrm_orcl
oracle   10032     1  0 00:58 ?        00:00:00 ora_psp0_orcl
oracle   10034     1  0 00:58 ?        00:00:01 ora_dia0_orcl
oracle   10036     1  0 00:58 ?        00:00:00 ora_mman_orcl
oracle   10038     1  0 00:58 ?        00:00:00 ora_dbw0_orcl
oracle   10040     1  0 00:58 ?        00:00:00 ora_lgwr_orcl
oracle   10042     1  0 00:58 ?        00:00:00 ora_ckpt_orcl
oracle   10044     1  0 00:58 ?        00:00:00 ora_smon_orcl
oracle   10046     1  0 00:58 ?        00:00:00 ora_reco_orcl
oracle   10048     1  0 00:58 ?        00:00:00 ora_mmon_orcl
oracle   10050     1  0 00:58 ?        00:00:00 ora_mmnl_orcl
oracle   10052     1  0 00:58 ?        00:00:00 ora_d000_orcl
oracle   10054     1  0 00:58 ?        00:00:00 ora_s000_orcl
oracle   15675  9806  0 01:59 pts/0    00:00:00 ps -ef
oracle   15676  9806  0 01:59 pts/0    00:00:00 grep --color=auto oracle
$ ipcs -a

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x011268f0 458753     root       600        1000       9
0x00000000 524290     oracle     660        4096       0
0x00000000 557059     oracle     660        4096       0
0x2a1ee740 589828     oracle     660        4096       0

------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0x19ba9600 1310738    oracle     660        154
</code></pre>

<p>由 <code>smon</code>、<code>pmon</code> <code>lgwr</code> 等进程可以看出此阶段创建了多个后台进程，并首次报告使用了共享内存和信号量。</p>

<h6 id="3-2-4-打开告警文件和跟踪文件">3.2.4 打开告警文件和跟踪文件</h6>

<p>数据库的启动过程记录在警告追踪文件中，该警告追踪文件中包括数据库启动信息，它存放在参数<code>BACKGOUND_DUMP_DEST</code> 定义的目录下，警告日志的名字为 <code>alert_&lt;sid&gt;.log</code>，<code>sid</code> 是实例的名称：</p>

<pre><code class="language-sql">SQL&gt; show parameter background_dump_dest;

NAME			           TYPE               VALUE
-------------------- -------------------------------------------------
background_dump_dest  string  /data/oracle/diag/rdbms/orcl/orcl/trace
</code></pre>

<p>进入到目录查看警告日志关于 <code>startup nomount</code> 过程记录：</p>

<pre><code>$ more alert_orcl.log
Fri Nov 11 17:04:51 2016
Starting ORACLE instance (normal)
LICENSE_MAX_SESSION = 0
LICENSE_SESSIONS_WARNING = 0
Shared memory segment for instance monitoring created
Picked latch-free SCN scheme 3
Using LOG_ARCHIVE_DEST_1 parameter default value as USE_DB_RECOVERY_FILE_DEST
Autotune of undo retention is turned on.
IMODE=BR
ILAT =27
LICENSE_MAX_USERS = 0
SYS auditing is disabled
Starting up:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options.
Using parameter settings in client-side pfile /data/oracle/admin/orcl/pfile/init.
</code></pre>

<p>Oracle 实例的后台进程会在遇到问题的时候将日志写入跟踪文件中。数据库的跟踪文件在目录由 <code>BACKGOUND_DUMP_DEST</code> 参数指定，最大大小由 <code>MAX_DUMP_FILE_SIZE</code> 指定，默认为<code>UNLIMITED</code>。</p>

<pre><code class="language-sql">SQL&gt; show parameter user_dump_dest;

NAME				     TYPE
------------------------------------ ----------------------
VALUE
------------------------------
user_dump_dest			     string
/data/oracle/diag/rdbms/orcl/o
rcl/trace
SQL&gt; show parameter max_dump_file_size;

NAME				     TYPE
------------------------------------ ----------------------
VALUE
------------------------------
max_dump_file_size		     string
unlimited
</code></pre>

<h4 id="3-3-装载数据库-nomunt-mount">3.3 装载数据库 <code>nomunt --&gt; mount</code></h4>

<h6 id="3-3-1-装载数据库概述">3.3.1 装载数据库概述</h6>

<p>装载数据库就是把数据库文件和实例关联起来，包括以下三个步骤：</p>

<ul>
<li>Oracle根据参数文件 <code>SPFILE</code> 中的参数找到控制文件</li>
<li>打开控制文件</li>
<li>从控制文件获得数据字典和重做日志文件的名字及位置</li>
</ul>

<p>完成以上三步，没有任何错误的情况下，Oracle 就已经把实例和数据库关联起来了。</p>

<p>装载数据库有两种方式：</p>

<ul>
<li>一是直接启动数据库到 <code>mount</code> 状态：<code>startup mount</code></li>
<li>二是如果数据库已经启动到 <code>nomount</code> 状态，使用 <code>alter database mount</code> 把数据库切换到<code>mount</code> 状态</li>
</ul>

<p><code>alert database mount</code>：</p>

<pre><code class="language-sql">SQL&gt; alter database mount;

Database altered.
</code></pre>

<p><code>startup mount</code>：</p>

<pre><code>SQL&gt; shutdown immediate;
ORA-01109: database not open


Database dismounted.
ORACLE instance shut down.
SQL&gt; startup mount;
ORACLE instance started.

Total System Global Area 3273641984 bytes
Fixed Size		    2217792 bytes
Variable Size		 2432698560 bytes
Database Buffers	  822083584 bytes
Redo Buffers		   16642048 bytes
Database mounted.
</code></pre>

<h6 id="3-3-2-可以查询控制文件">3.3.2 可以查询控制文件</h6>

<p>这个时候我们就可以查询控制文件、数据文件和重做日志文件了。</p>

<pre><code class="language-sql">SQL&gt; select status from v$instance;

STATUS
------------------------
MOUNTED

SQL&gt; select name from v$controlfile;

NAME
--------------------------------------------------------------------------------
/data/oracle/oradata/orcl/control01.ctl
/data/oracle/flash_recovery_area/orcl/control02.ctl

SQL&gt; select name from v$datafile;

NAME
--------------------------------------------------------------------------------
/data/oracle/oradata/orcl/system01.dbf
/data/oracle/oradata/orcl/sysaux01.dbf
/data/oracle/oradata/orcl/undotbs01.dbf
/data/oracle/oradata/orcl/users01.dbf
/data/oracle/oradata/orcl/example01.dbf
/data/oracle/oradata/orcl/SoftwareManagement.dbf

6 rows selected.

SQL&gt; select member from v$logfile;

MEMBER
--------------------------------------------------------------------------------
/data/oracle/oradata/orcl/redo03.log
/data/oracle/oradata/orcl/redo02.log
/data/oracle/oradata/orcl/redo01.log

</code></pre>

<h6 id="3-3-3-不能查询表-视图">3.3.3 不能查询表、视图</h6>

<p>但此时还不能查询数据库文件，如表和视图。所以对于普通用户而言，这个时候数据库还是不可用的。只有等到经历了最后一步 <code>打开数据库</code> 之后，才能使用数据库。</p>

<pre><code class="language-sql">SQL&gt; select * from tab;
select * from tab
              *
ERROR at line 1:
ORA-01219: database not open: queries allowed on fixed tables/views only

SQL&gt; select * from scott.dept;
select * from scott.dept
                    *
ERROR at line 1:
ORA-01219: database not open: queries allowed on fixed tables/views only
</code></pre>

<h4 id="3-4-打开数据库-mount-open">3.4 打开数据库 <code>mount --&gt; open</code></h4>

<p>打开数据库时，实例将打开所有处于联机状态的数据文件和重做日志文件。</p>

<p>在此期间，Oracle 服务器将校验所有的数据文件和联机日志文件能否打开，并对数据库作一致性检查。</p>

<ul>
<li>如果出现一致性错误，<code>SMON</code> 进程将启动实例恢复</li>
<li>如果任一数据文件或联机日志文件丢失，Oracle 服务器将报错</li>
</ul>

<p>只有将数据库设置为打开状态后，数据库才处于正常状态，这时普通用户才能够访问数据库。</p>

<p>打开数据库也有两种方式。</p>

<p><strong>一是使用 <code>alter</code> 命令。</strong></p>

<pre><code class="language-sql">&gt;SQL alter database open;

Database altered.

SQL&gt; select status from v$instance;

STATUS
------------------------
OPEN

</code></pre>

<p><strong>二是直接通过 <code>startup</code> 命令启动。</strong></p>

<p><code>startup</code> 命令会逐步完成数据库启动的三个步骤（创建实例、装载数据库、打开数据库），将数据库启动到 <code>open</code> 状态：</p>

<pre><code class="language-bash">SQL&gt; startup
ORACLE instance started.

Total System Global Area 3273641984 bytes
Fixed Size		    2217792 bytes
Variable Size		 2432698560 bytes
Database Buffers	  822083584 bytes
Redo Buffers		   16642048 bytes
Database mounted.
Database opened.
</code></pre>

<p>启动之后，就可以访问数据文件了：</p>

<pre><code class="language-sql">SQL&gt; select * from scott.dept;

    DEPTNO DNAME			LOC
---------- ---------------------------- --------------------------
	10 ACCOUNTING			NEW YORK
	20 RESEARCH			DALLAS
	30 SALES			CHICAGO
	40 OPERATIONS			BOSTON
</code></pre>

<h2 id="四-关闭数据库">四. 关闭数据库</h2>

<p>与启动数据库顺序相反，也分三个步骤：</p>

<ul>
<li><code>CLOSE</code>  关闭数据库（关闭数据文件）</li>
<li><code>DISMOUNT</code> 卸载数据库（关闭控制文件）</li>
<li><code>SHUTDOWN</code> 关闭 Oracle 实例</li>
</ul>

<p>同时关闭模式也有多种。</p>

<h4 id="4-1-normal">4.1. NORMAL</h4>

<p>正常的关闭方式。如果对于关闭数据库的时间没有限制，通常采用这种方式。</p>

<p>以 <code>NORMAL</code> 方式关闭数据库，Oracle 将执行如下操作：</p>

<ol>
<li>阻止任何用户建立新的连接</li>
<li>等待当前所有正在连接的用户主动断开连接</li>
<li>当前所有用户的都断开连接后，将立即关闭数据库</li>
</ol>

<h4 id="4-2-transaction">4.2. TRANSACTION</h4>

<p>事务关闭方式，它的首要任务是保证当前所有活动的事务都可以被提交，并在尽可能短的时间内关闭数据库。</p>

<p>以事务方式关闭，Oracle将执行如下操作：</p>

<ol>
<li>阻止用户建立新连接和开始新事务</li>
<li>等待所有活动事务提交后，再断开用户连接</li>
<li>当所有活动事务提交完毕，用户断开连接后，关闭数据库</li>
</ol>

<h4 id="4-3-immediate">4.3. IMMEDIATE</h4>

<p>立即关闭方式，可以较快且安全的关闭数据库，是 DBA 经常采用的关闭数据库的方式。</p>

<p>立即关闭方式 Oracle执行如下操作：</p>

<ol>
<li>阻止用户建立新的连接和开始新的事务</li>
<li>中断当前事务，回滚未提交事务</li>
<li>强制断开所有用户连接和执行检查点把脏数据写到数据文件中</li>
<li>关闭数据库</li>
</ol>

<h2 id="五-为什么分为三步">五. 为什么分为三步</h2>

<p>现在问题来了，明明一步就可以把数据库启动起来，为什么 Oracle 要很麻烦地分为三步呢？</p>

<p>这样的步骤，对于普通用户来说是多余的，但对于 DBA 来说确实非常重要的。因为这三个步骤中，每一步都会启动对应的进程打开对应的文件，所以维护的时候，我们就可以准对具体的问题，在数据库的某种状态下进行数据库维护工作。</p>

<p><strong>nomount 状态</strong></p>

<p><code>nomount</code> 状态不打开任何的控制文件及数据文件，所以我们可以在此阶段数据库创建、控制文件重建、特定的备份恢复等操作。</p>

<p><strong>mount 状态</strong></p>

<p>在加载完成以后，数据库还不可以被访问，所以在此阶段我们可以：</p>

<ul>
<li>重命名数据文件，移动数据文件位置等</li>
<li>启用或关闭重做日志文件的归档及非归档模式</li>
<li>实现数据库的完全恢复</li>
</ul>

<h2 id="六-常见连接错误">六. 常见连接错误</h2>

<h4 id="1-未启动数据库实例">1. 未启动数据库实例</h4>

<pre><code>Connection Failed
ORA-12514: TNS:listener does not currently know of service requested in connect descriptor
</code></pre>

<h4 id="2-未启动监听器">2. 未启动监听器</h4>

<pre><code>Oracle Connection Failed
ORA 12541: TNS:no listener
</code></pre>

<hr />

<p>参考：</p>

<ul>
<li><a href="https://docs.oracle.com/cd/B28359_01/server.111/b28310/start001.htm#ADMIN10063">Starting Up a Database</a></li>
<li><a href="http://blog.itpub.net/9399028/viewspace-682015/">Oracle SGA详解</a></li>
<li><a href="http://blog.itpub.net/25264937/viewspace-694917/">Oracle之内存结构（SGA、PGA）</a></li>
<li><a href="http://www.dongcoder.com/detail-441242.html">Oracle 数据库启动过程</a></li>
<li><a href="http://blog.itpub.net/29620680/viewspace-1153413/">oracle数据库启动过程大揭秘 </a></li>
<li><a href="http://www.zhaokongnuan.com/2015/01/03/Oracle学习交流（二）-oracle体系结构及启动流程/">Oracle学习交流（二）&ndash;oracle体系结构及启动流程</a></li>
<li><a href="http://blog.csdn.net/leshami/article/details/5542983">Oracle 数据库实例启动关闭过程</a></li>
<li><a href="http://www.jellythink.com/archives/1007">Oracle学习笔记——数据库启动原理</a></li>
</ul>

<hr />

<blockquote>
<p>Github Issues <a href="https://github.com/nodejh/nodejh.github.io/issues/35">https://github.com/nodejh/nodejh.github.io/issues/35</a></p>
</blockquote>
                </section>
            </article>

            
                <a class="twitter" href="https://twitter.com/intent/tweet?text=http%3a%2f%2fnodejh.com%2fposts%2funderstand-the-oracle-startup-process%2f - %e6%b7%b1%e5%85%a5%e7%90%86%e8%a7%a3%20Oracle%20%e5%90%af%e5%8a%a8%e5%8e%9f%e7%90%86 by @nodejh"><span class="icon-twitter"> tweet</span></a>

<a class="facebook" href="#" onclick="
    window.open(
      'https://www.facebook.com/sharer/sharer.php?u='+encodeURIComponent(location.href),
      'facebook-share-dialog',
      'width=626,height=436');
    return false;"><span class="icon-facebook-rect"> Share</span>
</a>

            

            
                <div id="disqus_thread"></div>
<script type="text/javascript">
    var disqus_shortname = 'nodejh'; 

     
    (function() {
        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
        dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>

            

            

            <footer id="footer">
    
        <div id="social">

	
	
    <a class="symbol" href="https://www.facebook.com/nodejh">
        <i class="fa fa-facebook-square"></i>
    </a>
    
    <a class="symbol" href="https://www.github.com/nodejh">
        <i class="fa fa-github-square"></i>
    </a>
    
    <a class="symbol" href="https://www.twitter.com/nodejh">
        <i class="fa fa-twitter-square"></i>
    </a>
    


</div>

    
    <p class="small">
    
       © Copyright 2018 <i class="fa fa-heart" aria-hidden="true"></i> 
    
    </p>
    <p class="small">
        Powered by <a href="http://www.gohugo.io/">Hugo</a> Theme By <a href="https://github.com/nodejh/hugo-theme-cactus-plus">nodejh</a>
    </p>
</footer>

        </section>

        <script src="http://nodejh.com/js/jquery-2.2.4.min.js"></script>
<script src="http://nodejh.com/js/main.js"></script>
<script src="http://nodejh.com/js/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>




  
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-84989670-1', 'auto');
ga('send', 'pageview');
</script>





    </body>
</html>
